<?php
namespace Blade;

/**
 * Blade 模板引擎
 *
 * 变量输出      {{ $name; }}
 * 过滤器使用    {{  csrf_token() }}
 * 

 */
class Blade
{
    const VERSION = '1.0.0';

    /**
     * @var $debug 布尔值 默认false
     * Debug为false时，如果生成了缓存，则仅仅读取缓存的模板，开发时请设置为true，否则您对模板的修改不会生效
     */
    private $debug;

    
    public $cache;

    private $compression;

    private $templateClassPrefix = '__template_';

    private $templatePath = '';


    //注册的模板函数
    private $rules     = [];

    //注册的模板函数
    private $functions = [];

    public function __construct($options=[]){
        $options = array_merge([
            'debug' 			=> false,
            'cache' 			=> false,
            'charset' 			=> 'UTF-8',
            'compression' 		=> false,
        ], $options);

        $this->debug = $options['debug'];
        $this->compression = $options['compression'];

        //初始化编译(正则替换)规则
        $this->rules = require __DIR__ . '/rules.php';

        //初始化缓存组件
        if( $options['cache'] ){
            $this->cache = new Cache\FilesystemCache($options['cache']);
        }else{
            $this->cache = new Cache\FilesystemCache(dirname(__DIR__));
        }
        
    }


    public function registerFunction($name, $callback){
    	$this->functions[$name] = $callback;
    }

    /**
     * 注册@命名
     */
    public function regsiterCommand($name, $callback)
    {

    }

    public function getTemplatePath($name)
    {
        return $this->templatePath . DIRECTORY_SEPARATOR . $name . ".blade.php";
    }

    public function setTemplatePath($path)
    {
        return $this->templatePath = trim($path, '/');
    }

    /**
     * 读取原始模板文件
     * @param  $viewFile 模板文件路径
     * @return 返回模板文件文本内容
     */
    public function readTemplate($viewFile)
    {
    	if( $this->compression ){
    		return str_replace(["\r\n", "\r", "\n"], '', file_get_contents($viewFile));
    	}
        if( file_exists($viewFile) ){
            return file_get_contents($viewFile);
        }

        if( file_exists($this->getTemplatePath($viewFile)) ){
            return file_get_contents($this->getTemplatePath($viewFile));
        }
    	   
        throw new \Exception("模板不存在 {$viewFile}");
    }

    /**
     * @include 标签解析
     * @param $vars  @include标签的参数部分字符串
     * @return include实际要调用的模板文件名
     * 调用代码 @include('footer', ['title' => $title])
     * includeMatch($string) $string = 'footer', ['title' => $title];
     * 将返回 footer 
     */
    public function includeMatch($vars)
    {
        $first = substr($vars, 0, 1);
        $vars = ltrim($vars, $first);

        return substr($vars, 0, strpos($vars, $first));
    }

    /**
     * 编译模板文件
     * @param  $content 模板文件文本
     * @return 返回编译后的php代码
     */
    public function compileTemplate($content, $name='')
    {
		list($pattern, $sourcecode) = $this->rules();

        //判断是否有include
        $includePattern = '/@include\((.{3,})\)/';
        if( preg_match_all($includePattern, $content, $matches) > 0 ){
            foreach ($matches[1] as $key => $value) {
                $includeTemplateName = $this->includeMatch($value);
                $this->loadTemplate($includeTemplateName);   
            }
        }

        //判断是否有布局 将布局一起编译
        $extendsPattern = '/@extends\((.{3,})\)/';
        if( preg_match($extendsPattern, $content, $matches) > 0 ){
            list($_, $layoutName) = $matches;
            $layoutName = trim($layoutName, substr($layoutName, 0, 1));
            $this->loadTemplate($layoutName);

            $usedLayout = true;
        }


        if( isset($usedLayout) ){
            $compileContent = preg_replace($pattern, $sourcecode, $content);
            // $compileContent .= "\n \n";
            $compileContent .= '<?php /*include layout templates*/ echo $this->include(\''.$layoutName.'\', get_defined_vars()) ?>';

        }else{
            $compileContent = preg_replace($pattern, $sourcecode, $content);
        }

        $annotation = '<?php /* compile by templates ' . $this->getTemplatePath($name) . '*/ ?>';
    	return $compileContent . $annotation;
    }

    /**
     * 获得编译的正则规则和要替换的php代码
     */
    public function rules(array $pattern=[], array $sourcecode=[])
    {
		foreach ($this->rules as $key => $value) {
			$pattern[]    = "#". trim($key,'#') ."#";
			$sourcecode[] = $value;
		}
		return [$pattern, $sourcecode];
    }

    public function loadTemplate($name)
    {
        $cacheFile = $this->cache->generateKey($name);

        /**
         * 如果缓存文件存在并且未过期则使用缓存
         * debug开启的话每次都会编译 永不使用缓存
         */
        if( $this->debug === false &&  $this->cache->exists($cacheFile) ){
            return $cacheFile;
        }

        /**
         * 缓存不存在或者已经过期
         * 编译模板文件并且写入缓存
         */
        $templateSourcecode = $this->compileTemplate($this->readTemplate($name), $name);
        $this->cache->write($cacheFile, $templateSourcecode);

        //返回可用的缓存文件供使用
        return $cacheFile;
    }



    public function load($name)
    {
        return new TemplateWrapper($this, $this->loadTemplate($name));
    }



	public function renderFile($viewFile, $params)
    {
        return $this->load($viewFile)->render($params);
	}


}